using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Cityship
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;


        float framesThisSecond;

        int currentDeckIndex = 0;
        Random rand;

        Camera camera;
        Vector2 screenCenter;

        Ship ship;
        const float tileSize = 16; //Tile size in pixels (height&width)
        SpriteFont myFont;

        string message;
        string message2;

        KeyboardState old_k_state;
        MouseState old_m_state;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);

            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 600;

            //graphics.IsFullScreen = true;
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            rand = new Random();

            camera = new Camera();
            screenCenter = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2, graphics.GraphicsDevice.Viewport.Height / 2);
            camera.Pos = screenCenter;

            IsMouseVisible = true;
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            myFont = Content.Load<SpriteFont>("segoe");
            message = "test";
            message2 = "";

            Utility.Initialize();
            SpriteSet.Initialize(Content);
            ShipBuilder.Initialize(Content);
            SpriteSet.LoadContentItems();
            NewShip();

            Deck currentDeck = ship.GetDeckByIndex(currentDeckIndex);

            camera.Pos += new Vector2((currentDeck.GetWidth / 2) * tileSize, (currentDeck.GetHeight / 2) * tileSize)-screenCenter;
        }

        private void NewShip()
        {
            ship = new Ship("My Ship");
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            KeyboardState k_state = Keyboard.GetState();
            MouseState m_state = Mouse.GetState();

            Deck deck = ship.GetDeckByIndex(currentDeckIndex);

            Vector2 m_position = new Vector2(m_state.X, m_state.Y);

            if (m_state.MiddleButton == ButtonState.Pressed)
            {
                camera.Move(((m_position-screenCenter)*0.1f)/camera.Zoom);
            }

            if (m_state.ScrollWheelValue != old_m_state.ScrollWheelValue)
            {
                if (m_state.ScrollWheelValue > old_m_state.ScrollWheelValue)
                {
                    camera.Zoom *= 1.25f;
                }
                else
                {
                    camera.Zoom /= 1.25f;
                }
            }


            if (deck != null)
            {
               

                Vector3 cameraOffset = (camera.get_transformation(graphics.GraphicsDevice).Translation);
                Vector2 position = new Vector2(m_position.X - cameraOffset.X, m_position.Y - cameraOffset.Y);

                position /= tileSize;
                position /= camera.Zoom;
                message2 = "X:"+(int)position.X+" Y:"+(int)position.Y;
                message2 += "\n"+Environment.TickCount.ToString();

                if (m_state.LeftButton == ButtonState.Pressed)
                {

                    if (k_state.IsKeyDown(Keys.P))
                    {
                        deck.TileGrid[(int)position.X, (int)position.Y].ChangePressure(0.15f);
                    }
                    else if (k_state.IsKeyDown(Keys.N))
                    {
                        deck.EqualizePressure(position, 3);
                    }
                    else
                    {
                        deck.ChangeTileAtPosition((int)position.X, (int)position.Y, TileType.Wall);
                    }


                }

                if (m_state.RightButton == ButtonState.Pressed)
                {
                    if (k_state.IsKeyDown(Keys.P))
                    {
                        deck.TileGrid[(int)position.X, (int)position.Y].ChangePressure(-0.15f);
                    }
                    else
                    {
                        deck.ChangeTileAtPosition((int)position.X, (int)position.Y, TileType.Floor);
                    }
                }

                if (k_state.IsKeyDown(Keys.A))
                {
                    for (int x = 0; x < 200; x++)
                    {
                        deck.ChangeTileAtPosition(rand.Next(0, deck.GetWidth), rand.Next(0, deck.GetHeight), TileType.Wall);
                    }
                }
                if (k_state.IsKeyDown(Keys.D))
                {
                    deck.ChangeTileAtPosition(rand.Next(0, deck.GetWidth), rand.Next(0, deck.GetHeight), TileType.Floor);
                }
            }

            if (k_state.IsKeyDown(Keys.R) && old_k_state.IsKeyUp(Keys.R))
            {
                ship.GetDeckByIndex(currentDeckIndex).Outline();
            }

            if (k_state.IsKeyDown(Keys.E) && old_k_state.IsKeyUp(Keys.E))
            {
                ship.GetDeckByIndex(currentDeckIndex).Clear();
            }

            if (k_state.IsKeyDown(Keys.D1) && old_k_state.IsKeyUp(Keys.D1))
            {
                currentDeckIndex = 0;
            }

            if (k_state.IsKeyDown(Keys.D2) && old_k_state.IsKeyUp(Keys.D2))
            {
                currentDeckIndex = 1;
            }

            old_k_state = k_state;
            old_m_state = m_state;

            //Logic
            ship.UpdateEntities(gameTime);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            Vector2 tileSizeOffset = new Vector2(tileSize, tileSize) / 2;
            Deck deck = ship.GetDeckByIndex(currentDeckIndex);


            //Draw Tiles/Entities
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, camera.get_transformation(graphics.GraphicsDevice));

            //Dead Entities drawn first.
            foreach (Entity entity in ship.DeadEntities)
            {
                Texture2D sprite = SpriteSet.Entity[entity.spriteName];
                spriteBatch.Draw(sprite, (entity.Location * tileSize), null, Color.Gray, entity.Rotation, new Vector2(sprite.Width / 2, sprite.Height / 2), entity.Scale, SpriteEffects.None, 1f);

            }
            
            //Tiles
            for (int x = 0; x < deck.GetWidth; x++)
            {
                for (int y = 0; y < deck.GetHeight; y++)
                {
                    Tile tile = deck.TileGrid[x, y];
                    if (tile != null && tile.Type != TileType.Nothing)
                    {
                        string tiletypename = tile.GetType().ToString();
                        tiletypename += "";
                        Texture2D sprite = SpriteSet.GetTileSet(tile.Type)[tile.SpriteName];

                        if (tile.Type == TileType.Wall | tile.Type == TileType.Floor)
                        {
                            spriteBatch.Draw(sprite, (new Vector2(x, y) * tileSize) + tileSizeOffset, null, new Color(1f, 1f - tile.Pressure, 1f - tile.Pressure), tile.Rotation, tileSizeOffset, 1f, SpriteEffects.None, 1f);
                        }
                    }
                }
            }

            //Living/active entities
            foreach (Entity entity in deck.Entities)
            {
                if (!entity.Dead)
                {
                    Texture2D sprite = SpriteSet.Entity[entity.spriteName];
                    spriteBatch.Draw(sprite, (entity.Location * tileSize), null, Color.White, entity.Rotation, new Vector2(sprite.Width / 2, sprite.Height / 2), entity.Scale, SpriteEffects.None, 1f);
                }
            }
            spriteBatch.End();


            //Draw UI
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null);


            framesThisSecond = MathHelper.SmoothStep(framesThisSecond, 1000f / (float)gameTime.ElapsedGameTime.Milliseconds, 0.25f);

            message = "FPS: " + framesThisSecond.ToString("N1");
            spriteBatch.DrawString(myFont, message, new Vector2(400, 40), Color.White);
            spriteBatch.DrawString(myFont, message2, new Vector2(400, 60), Color.White);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
